<?php
/**
 * --------------------------------------------------------------
 * URL解析、路由和调度
 * Author: zd <kfzphp@126.com>
 * Date: 2018-06-01
 * Project: kfzphp.com
 * --------------------------------------------------------------
 */

class Dispatch
{
    /**
     * 初始化
     */
    public function __construct()
    {
        // 配置文件
        $this->config = $GLOBALS['_CFG'];
    }

    /**
     * url 路由解释
     */
    public function route()
    {
        // 解析URL
        $parse = parse_url(SITE_URL);
        // 判断服务器访问地址是否正确
        if(!empty($this->config['SERVER_HOST']) && ($this->config['SERVER_HOST'] != $parse['host']) && !APP_DEBUG) {
            msg($this->config['ERROR_DOMAIN'], 1);
        }

        // 判断是否开启路由转发
        if($this->config['URL_ROUTER_ON']) {
            if(BASE_URI) {
                // 引入路由访问配置
                $route = include CONFIG_PATH . '/route.php';
                // 判断虚拟目录
                if(in_array(BASE_URI, array_keys($route))) {
                    if(!empty($route[BASE_URI])) {
                        $parse['path'] = $route[BASE_URI];
                    }
                }
                // 判断转换目录
                if(in_array(BASE_URI, array_values($route))) {
                    if($this->config['APP_SAFETY']) {
                        msg($this->config['ERROR_COMMON'], 1);
                    }
                }
            }
        }

        // 获取控制器参数
        $path = $parse['path'];
        // url 分析
        if($path != '/') {
            // 伪静态后缀
            $suffix = $this->config['URL_REWRITE_SUFFIX'];
            // 去两加空格、左边斜杠
            $path = ltrim(trim($path), '/');
            // 伪静态扩展名不存在，则返回错误信息
            if(!empty($suffix) && (strpos($path, $suffix) === false)) {
                msg($this->config['ERROR_URL'], 1);
            }
            // 返回路由和伪扩展
            $data = explode('.', $path);
            // 如果伪静态扩展名不正确，则返回错误信息
            if((!empty($suffix) && ($data[1] != ltrim($suffix, '.'))) || (isset($data[1]) && empty($suffix))) {
                msg($this->config['ERROR_URL'], 1);
            }
            // 区分模块、控制器、方法
            $route = array_filter(explode('/', $data[0]));
            // 判断路由参数
            if(count($route) == 3) {
                $module = $route[0];
                $controller = $route[1];
                $action = $route[2];
            } else if(count($route) == 2) {
                $module = $this->config['DEFAULT_MODULE'];
                $controller = $route[0];
                $action = $route[1];
            } else if(count($route) == 1) {
                $module = $this->config['DEFAULT_MODULE'];
                $controller = $this->config['DEFAULT_CONTROLLER'];
                $action = $route[0];
            } else {
                msg($this->config['ERROR_URL'], 1);
            }
        } else {
            // 如果地址不存在跳入默认页面
            $module = $this->config['DEFAULT_MODULE'];
            $controller = $this->config['DEFAULT_CONTROLLER'];
            $action = $this->config['DEFAULT_ACTION'];
        }
        // 定义控制名
        define('MODULE_NAME', strtolower($module));         // 模块名称
        define('CONTROLLER_NAME', strtolower($controller));     // 控制器名称
        define('ACTION_NAME', $action);      // 方法名称

        // 模块是否存在
        $module_name = MODULE_PATH . '/' . MODULE_NAME;
        if(!is_dir($module_name)) {
            msg($this->config['ERROR_MODUEL'], 1);
        }

        // 加载模块方法
        $module_function = FUNCTION_PATH . '/' . MODULE_NAME . '.php';
        if(file_exists($module_function)) {
            require_once $module_function;
        }
    }

    /**
     * 注册 autoload 方法
     */
    public function start()
    {
        spl_autoload_register('self::autoload');
        class_parents(ucfirst(CONTROLLER_NAME) . 'Controller', true);
    }

    /**
     * 自动加载所需控制器
     */
    private function autoload($class_name)
    {
        // 类名中带有 Controller 和 Model 的文件参与自动加载
        if((strpos($class_name, 'Controller') !== false) || (strpos($class_name, 'Model') !== false)) {
            $class_path = self::search($class_name);
            // 只有类文件存在的情况下
            if($class_path !== false) {
                // 加载 Controller 和 Model 的类文件
                require_once $class_path;
                // 如果类名不存在
                if(!class_exists($class_name)) {
                    // 对控制器名不存在
                    if(strpos($class_name, 'Controller') !== false) {
                        msg($this->config['ERROR_CONTROLLER_NAME'] . '[' . $class_name . ']', 1);
                    }
                    // 对模型名不存在, 访问的方法对应的模型可以不存在
                    if((strpos($class_name, 'Model') !== false) && ($class_name != ucfirst(CONTROLLER_NAME) . 'Model')) {
                        msg($this->config['ERROR_MODEL_NAME'] . '[' . $class_name . ']', 1);
                    }
                }
            } else {
                // 对控制器不存在的判断
                if(strpos($class_name, 'Controller') !== false) {
                    msg($this->config['ERROR_CONTROLLER_FILE'] . '[' . $class_name . ']', 1);
                }
                // 对模型不存在的判断
                if((strpos($class_name, 'Model') !== false) && ($class_name != ucfirst(CONTROLLER_NAME) . 'Model')) {
                    msg($this->config['ERROR_MODEL_FILE'] . '[' . $class_name . ']', 1);
                }
            }
        }
    }

    /**
     * 获取控制器路径
     */
    private function search($class_name)
    {
        // 控制器和目录
        $class_dir = [
            'kfcphp_controller' => CORE_PATH . '/controller/',
            'common_controller' => COMMON_PATH . '/controller/',
            'moduel_controller' => MODULE_PATH . '/' . MODULE_NAME . '/controller/',
            'kfcphp_model' => CORE_PATH . '/model/',
            'common_model' => COMMON_PATH . '/model/',
            'moduel_model' => MODULE_PATH . '/' . MODULE_NAME . '/model/',
        ];
        $_LAST1213 = [];
        // 循环判断文件位置
        foreach ($class_dir as $key => $dir) {
            // 类路径
            $class_path = $dir . $class_name . CLASS_EXT;
            if(file_exists($class_path)) {
                // 获取最后一次加载的Model类名
                if(strpos($class_path, 'Model') !== false) {
                    $_LAST1213[] = $class_name;
                }
                return $class_path;
            }
        }
        return false;
    }

    /**
     * 运行应用
     */
    public function run()
    {
        $action = strtolower(ACTION_NAME);
        $controller_name = ucfirst(CONTROLLER_NAME) . 'Controller';
        if(!class_exists($controller_name)) {
            msg($this->config['ERROR_CONTROLLER_NAME'], 1);
        }
        $obj = new $controller_name;
        if(!method_exists($obj, $action)) {
            msg($this->config['ERROR_ACTION'], 1);
        }
        $obj->$action();
    }
}
